const std = @import("std");
const db = @import("./db.zig");
const myzql = @import("myzql");
const String = @import("ztring").String;
const ResultSet = myzql.result.ResultSet;
const ResultRow = myzql.result.ResultRow;
const TextResultRow = myzql.result.TextResultRow;
const ResultRowIter = myzql.result.ResultRowIter;
const TextElemIter = myzql.result.TextElemIter;
const BinaryResultRow = myzql.result.BinaryResultRow;
const httpz = @import("httpz");
const teacher_model = @import("../models/teacher_model.zig");

pub fn add(teacher: *const teacher_model.Teacher) !bool {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const client = db.get_db_client();
    const prep_res = try client.prepare(
        allocator,
        "INSERT INTO teacher(name, number) VALUES (?, ?)",
    );
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    const param = .{
        teacher.Id.?,
        teacher.name.?,
        teacher.phone.?,
        teacher.tm.?,
    };
    _ = try client.execute(&prep_stmt, param);
    return true;
}

pub fn query(teacher: *const teacher_model.Teacher, response: *httpz.Response) !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    var sql = String.init(allocator);
    defer sql.deinit();
    try sql.concat("SELECT * FROM teacher ");
    try concat_cols_push(&sql, "WHERE ", teacher, "AND ");
    const client = db.get_db_client();
    const prep_res = try client.prepare(allocator, sql.str());
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    const query_res = try client.executeRows(&prep_stmt, .{});
    const rows: ResultSet(BinaryResultRow) = try query_res.expect(.rows);
    const res_teachers = try rows.iter().tableStructs(teacher_model.Teacher, allocator);
    defer res_teachers.deinit(allocator);

    var stander_arr = std.ArrayList(teacher_model.TeacherStander).init(std.heap.page_allocator);
    defer stander_arr.deinit();
    for (res_teachers.struct_list.items) |item| {
        const stander = teacher_model.model_2_stander(&item);
        try stander_arr.append(stander);
    }
    std.debug.print("stander_arr.items[0].tm={s}", .{stander_arr.items[0].tm.?});
    try response.json(.{ .result = stander_arr.items }, .{});
}

pub fn query_by_pk(Id: i32) !teacher_model.Teacher {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const client = db.get_db_client();
    const prep_res = try client.prepare(allocator, "SELECT * from teacher WHERE Id = ?");
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    const query_res = try client.executeRows(&prep_stmt, .{Id});
    const rows: ResultSet(BinaryResultRow) = try query_res.expect(.rows);
    const rows_iter = rows.iter();
    while (try rows_iter.next()) |row| {
        var teacher: teacher_model.Teacher = undefined;
        try row.scan(&teacher);
        return teacher;
    }

    return teacher_model.Teacher{};
}

pub fn update(teacher: *const teacher_model.Teacher) !bool {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    var sql = String.init(allocator);
    defer sql.deinit();
    try sql.concat("UPDATE teacher SET ");
    try concat_cols_push(&sql, "", teacher, ",");
    try sql.concat(" WHERE Id = ?");

    const client = db.get_db_client();
    const prep_res = try client.prepare(allocator, sql.str());
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    _ = try client.execute(&prep_stmt, .{teacher.Id.?});

    return true;
}

pub fn delete(Id: i32) !bool {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    const client = db.get_db_client();
    const prep_res = try client.prepare(allocator, "DELETE FROM teacher WHERE Id = ?");
    defer prep_res.deinit(allocator);
    const prep_stmt = try prep_res.expect(.stmt);
    _ = try client.execute(&prep_stmt, .{Id});
    return true;
}

fn concat_cols_push(buffer: *String, prefix: []const u8, param: *const teacher_model.Teacher, conj: []const u8) !void {
    var first = true;
    if (param.name != null) {
        if (!first) {
            try buffer.concat(conj);
        } else {
            try buffer.concat(prefix);
        }
        first = false;
        try buffer.concat("name = '");
        try buffer.concat(param.name.?);
        try buffer.concat("'");
    }
    if (param.phone != null) {
        if (!first) {
            try buffer.concat(conj);
        } else {
            try buffer.concat(prefix);
        }
        first = false;
        try buffer.concat("phone = '");
        try buffer.concat(param.phone.?);
        try buffer.concat("'");
    }
}
